package juc.popular.aqs;

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * (sai mer fer)
 * Semaphore是一个计数信号量,常用于限制可以访问某些资源（物理或逻辑的）线程数目
 * * {@link Semaphore#Semaphore(int)} 构造方法
 * * {@link Semaphore#Semaphore(int, boolean)}  构造方法,可以指定是否公平
 * * {@link Semaphore#acquire()}获取一个许可
 * * {@link Semaphore#release()} 释放一个许可
 * <p>
 * <p>
 * 应用场景一:
 * * 假若一个工厂有5台机器,但是有8个工人,一台机器同时只能被一个工人使用,只有使用完了,其他工人才能继续使用
 * <p>
 * 应用场景二:
 * * 可以用于做流量控制,特别公用资源有限的应用场景,比如数据库连接
 * * 假如有一个需求,要读取几万个文件的数据,因为都是I/O密集型任务,我们可以启动10个线程并发的读取,
 * * 但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有3个,这时我们必须控制只有十个线程同时
 * * 获取数据库连接保存数据,否则会报错无法获取数据库连接
 *
 * @author 王霄
 * @date 2021/9/24 15:30
 **/
public class SemaphoreDemo {

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(5);
        IntStream.range(0, 8).forEach(i -> new Worker("工人" + i, semaphore).start());
    }

    public static class Worker extends Thread {
        private final Semaphore semaphore;

        public Worker(String name, Semaphore semaphore) {
            super(name);
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.printf("%s工作中%n" , getName());
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException ignored) {
            } finally {
                semaphore.release();
            }
            System.out.printf("%s工作结束%n" , getName());
        }
    }
}
